/*
 * $Id: hbdoc.prg 17773 2012-07-04 10:45:31Z riztan $
 */

/*
 * Harbour Project source code:
 * Document generator
 *
 * Copyright 2009 April White <april users.sourceforge.net>
 * www - http://harbour-project.org
 *
 * Portions of this project are based on hbdoc
 *    Copyright 1999-2003 Luiz Rafael Culik <culikr@uol.com.br>
 *
 *    <TODO: list gen... methods used>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
 *
 * As a special exception, the Harbour Project gives permission for
 * additional uses of the text contained in its release of Harbour.
 *
 * The exception is that, if you link the Harbour libraries with other
 * files to produce an executable, this does not by itself cause the
 * resulting executable to be covered by the GNU General Public License.
 * Your use of that executable is in no way restricted on account of
 * linking the Harbour library code into it.
 *
 * This exception does not however invalidate any other reasons why
 * the executable file might be covered by the GNU General Public License.
 *
 * This exception applies only to the code released by the Harbour
 * Project under the name Harbour.  If you copy code from other
 * Harbour Project or Free Software Foundation releases into a copy of
 * Harbour, as the General Public License permits, the exception does
 * not apply to the code that you add in this way.  To avoid misleading
 * anyone as to the status of such modified files, you must delete
 * this exception notice from them.
 *
 * If you write modifications of your own for Harbour, it is your choice
 * whether to permit this exception to apply to your modifications.
 * If you do not wish that, delete this exception notice.
 *
 */

/** 
 * \file hbdoc.prg
 * \brief Programa que genera archivo que puede leer doxygen.
 * Una vez generado el archivo compatible, se invoca doxygen para generar
 * la documentación correspondiente.
 *
 * \bug el programa no esta incluyendo la ultima funcion del prg.
   Creo, se debe a que no adiciona los valores cuando llega al final del archivo fuente.
 */

#include "directry.ch"
#include "fileio.ch"

#include "hbdoc.ch"
#include "xhb.ch"
#include "common.ch"

ANNOUNCE HB_GTSYS
REQUEST HB_GT_CGI_DEFAULT

#define BASE_DIR ".." + hb_ps() + ".." + hb_ps()
#define ENDCOMMENT  "*"+"/"

STATIC s_aExclusions := { "class_tp.txt", "hdr_tpl.txt" }

STATIC aEndFunc      := {"CLASS ", "//EOF","/*EOF","METHOD ",;
                         "PROCEDURE ","PROCE ","FUNCTION ","FUNC "}

STATIC aSymbols       := { "FUNCTION",  ;
                           "PROCEDURE", ;
                           "ENDCLASS",  ;
                           "CLASS",     ;
                           "METHOD",    ;
                           "RETURN",    ;
                           ENDCOMMENT,        ;
                           "/"+"*"+"*",       ;
                           "/"+"*" }

#define  __FUNC    aSymbols[1]
#define  __PROC    aSymbols[2]
#define  __ENDC    aSymbols[3]
#define  __CLAS    aSymbols[4]
#define  __METH    aSymbols[5]
#define  __RETU    aSymbols[6]
#define  __EDOX    aSymbols[7]
#define  __IDOX    aSymbols[8]
#define  __COMM    aSymbols[9]

#translate  _ISFUNC( <cSymbol> )   =>   ( <cSymbol> = aSymbols[ 1 ] )
#translate  _ISPROC( <cSymbol> )   =>   ( <cSymbol> = aSymbols[ 2 ] )
#translate  _ISENDC( <cSymbol> )   =>   ( <cSymbol> = aSymbols[ 3 ] )
#translate  _ISCLAS( <cSymbol> )   =>   ( <cSymbol> = aSymbols[ 4 ] )
#translate  _ISMETH( <cSymbol> )   =>   ( <cSymbol> = aSymbols[ 5 ] )
#translate  _ISRETU( <cSymbol> )   =>   ( <cSymbol> = aSymbols[ 6 ] )
#translate  _ISEDOX( <cSymbol> )   =>   ( <cSymbol> = aSymbols[ 7 ] )
#translate  _ISIDOX( <cSymbol> )   =>   ( <cSymbol> = aSymbols[ 8 ] )
#translate  _ISCOMM( <cSymbol> )   =>   ( <cSymbol> = aSymbols[ 9 ] )


//MEMVAR p_hsSwitches
//#include "gclass.ch"

/** \brief Funcion Inicial
 */
PROCEDURE Main( ... )

   ProcessFolder( "./", {} )

RETURN


/** \brief Revisa el contenido de una carpeta, obtiene la lista de archivos y procesa cada uno de los fuentes encontrados. */
STATIC PROCEDURE ProcessFolder( cFolder, aContent ) // this is a recursive procedure
   LOCAL aFiles
   LOCAL nLen
   LOCAL idx
   LOCAL cExt

   LOCAL oFile

   //~ OutStd( ">>> " + cFolder + hb_eol() )

   cFolder += hb_ps()

   aFiles := Directory( cFolder + hb_osFileMask(), "D" )
   IF ( nLen := Len( aFiles ) ) > 0
      FOR idx := 1 TO nLen
         IF aFiles[ idx ][F_ATTR ] == "D"
            IF !( aFiles[ idx ][ F_NAME ] == "." ) .AND. ;
               !( aFiles[ idx ][ F_NAME ] == ".." )

               //IF ( p_hsSwitches[ "source" ] .OR. p_hsSwitches[ "contribs" ] ) /* .AND. ;
                  //hb_AScan( s_aSkipDirs, {| d | Lower( d ) == Lower( aFiles[ idx ][ F_NAME ] ) } ) == 0 

                  ProcessFolder( cFolder + aFiles[ idx ][ F_NAME ], @aContent )
                  //ProcessFolder( cFolder, @aContent )
               //ENDIF
            ENDIF
         ELSEIF hb_AScan( s_aExclusions, {| f | Lower( f ) == Lower( aFiles[ idx ][ F_NAME ] ) } ) == 0
            hb_FNameSplit( aFiles[ idx ][ F_NAME ], , , @cExt )
            IF Lower( cExt ) == ".prg"
//? "aqui"

               oFile := TPublic():New()
               oFile:lComment := .f.
               oFile:lIniFunc := .f.
               oFile:lIgnore  := .f.

               IF ! ProcessFile( cFolder + aFiles[ idx ][ F_NAME ], @aContent, oFile )
                  EXIT
               ENDIF
            ENDIF
         ENDIF
      NEXT
   ENDIF

   oFile := NIL

   RETURN

/** \brief Funcion para procesar archivo. */
/*
  * Extrae la información con la que genera el prg que es comprendido por doxygen
  */
STATIC FUNCTION ProcessFile( cFile, aContent, oFile )
   LOCAL aHandle := { 0, 0 } // file handle and position
   LOCAL cBuffer, cBufferCode, cTrimBuffer, cUpperBuffer
   LOCAL cDoxyBuffer:="", cLangCBuffer:=""
   LOCAL aFunction
   LOCAL cFuncName
   LOCAL lComment := .f.
   LOCAL lIniFunc := .f.
   LOCAL lIgnore  := .f.
   LOCAL lSymbol
   LOCAL nCount := 0

   If hb_ISNIL( oFile ) 
      Return NIL 
   EndIf

   oFile:cWWW        := "http://www.gtxbase.org/devel"
   oFile:cReposName  := "T-GTK"
   oFile:cReposPath  := "./src/gclass"
   oFile:cDoxyDir    := "./src"
   oFile:cFile       := StrTran( cFile, "./", "" )

   oFile:lIncSrc     := .f.
   oFile:lIniCode    := .f.
   oFile:cIniCode    := ""
   oFile:cStyleSheet := "shCoreEclipse.css"        
   oFile:cHLPath     := "syntax/"        
   //oFile:cHLPath     := "http://localhost/syntax/"        

   oFile:nLines      := 0

   oFile:lSymbol     := .f.

   oFile:lAddVal     := .t.
   oFile:cRetVal     := ""
   oFile:cTemp       := ""

   oFile:lIniFile    := .f.
   oFile:lEndFile    := .f.
   oFile:cIniFile    := ""
   oFile:cFileComment:= ""

   oFile:lIniSymbol  := .f.
   oFile:lIgnore     := .f.

   oFile:lIniComment := .f.
   oFile:lEndComment := .f.
   oFile:lComment    := .f.

   oFile:lIniDoxy    := .f.
   oFile:lDoxyComment:= .f.
   oFile:lEndDoxy    := .f.
   oFile:cDoxy       := ""

   oFile:lIniFunc    := .f.
   oFile:lFunction   := .f.
   oFile:lEndFunc    := .f.
   oFile:cPreFunc    := ""
   oFile:cFunc       := ""
   oFile:cFuncCode   := ""

   oFile:lReturn     := .f.

   oFile:lIniClass   := .f.
   oFile:lClass      := .f.
   oFile:lEndClass   := .f.
   oFile:cPreClass   := ""
   oFile:cClass      := ""
   oFile:cClassCode  := ""
   oFile:cClassName  := ""

   oFile:lIniMethod  := .f.
   oFile:lEndMethod  := .f.
   oFile:cMethod     := ""
   oFile:cMethodName := ""
   oFile:cPreMethod  := ""


   If ( aHandle[ 1 ] := FOpen( cFile ) ) == F_ERROR
      OutErr( "error: could not open " + cFile + ", " + hb_ntos( Abs( aHandle[ 1 ] ) ) + hb_eol() )
      RETURN .F.
   EndIf


   Do While FReadLn( @aHandle, @cBuffer, oFile )

      cBufferCode  := cBuffer
      cTrimBuffer  := ALLTRIM( cBuffer )
      cUpperBuffer := UPPER(cTrimBuffer)

      oFile:lSymbol := Get_Symbol( cUpperBuffer, oFile )
 
      If oFile:lSymbol

/*
         ? " symb> ",oFile:cSymbol
         ? oFile:nLines,"> ", cBuffer
if oFile:lIniFunc
         ? " Inició Funcion ", oFile:lIniFunc
         ? " Fin de Funcion ", oFile:lEndFunc
         ?
endif
if oFile:lFunction
         ? " En Funcion     ", oFile:lFunction
         ? " RETORNO        ", oFile:lReturn
         ? " Fin de Funcion ", oFile:lEndFunc
         ?
endif
if oFile:lIniComment
         ? " Inicio Comentario ", oFile:lIniComment
         ? " Fin Comentario    ", oFile:lEndComment
         ?
endif
if oFile:lIniDoxy
         ? " Inicio Comentario Doxy ", oFile:lIniDoxy
         ? " Fin Comentario Doxy    ", oFile:lEndDoxy
endif
?
?
*/

         /* Acciones relacionadas con symbolo de tipo funcion */
         If oFile:lIniFunc 
            if oFile:lEndFunc
               oFile:cFunc    += Doxy_Convert( oFile, "\"+"endcode_hb ", .t. ) + hb_eol()
               //oFile:cFunc    += "  * \"+"endcode " + hb_eol()
               oFile:cFunc    += "  "+ENDCOMMENT+" " + hb_eol()
               oFile:cFunc    += hb_eol() 
               oFile:cRetVal  += oFile:cFunc
               oFile:cFunc    := ""
               oFile:cRetVal  += oFile:cFuncCode + hb_eol() +"{"+hb_eol()+"}" +hb_eol()
            endif

            If !Empty( oFile:cPreFunc ) 
               oFile:cFunc := oFile:cPreFunc + oFile:cFunc
               oFile:cDoxy := ""
            EndIf
            oFile:cPreFunc := ""
            //oFile:cFunc := hb_eol()
            oFile:cFunc += " /"+"*"+"* " + hb_eol() 
            oFile:cFunc += Build_Params( cBuffer, .t., oFile ) 
            oFile:cFunc += "  * " + hb_eol()
            oFile:cFunc += "  * \fn " 
            oFile:cFunc += cBuffer + hb_eol()
            oFile:cFuncCode := cBuffer
            oFile:cFunc += Doxy_Convert( oFile, "\"+"code_hb", .t. )
            //oFile:cFunc += "  * \"+"code "  + hb_eol()
            //oFile:cFunc += "  * " + cBuffer + hb_eol()
            oFile:cFunc += cBuffer + hb_eol()

            oFile:lIniFunc := .f.
            oFile:lFunction:= .t.
            oFile:lEndFunc := .t.
            oFile:lReturn  := .f.
         EndIf


         /* Acciones relacionadas con symbolo de tipo CLASE */
         If oFile:lIniClass
            oFile:cMethod := ""
            If !Empty( oFile:cDoxy )
               oFile:cClass += hb_eol() + hb_eol() + oFile:cDoxy 
               oFile:cDoxy := ""
            EndIf
            If !Empty( oFile:cPreClass ) 
               oFile:cClass := oFile:cPreClass + oFile:cClass
               oFile:cPreClass := ""
               oFile:cDoxy := ""
            EndIf
            oFile:cClass += " /** " + hb_eol() 
            oFile:cClass += Build_Params( cBuffer, .t., oFile ) 
            oFile:cClass += "  * \class " 

            oFile:cClass += hb_TokenGet( cUpperBuffer, 2, " "  ) + hb_eol()
            oFile:cCLassCode := cBuffer
//            oFile:cClass += "  * " + cBuffer + hb_eol()
            oFile:cClass += "  "+ENDCOMMENT+ hb_eol()
            oFile:cClassName := Upper( hb_TokenGet( cTrimBuffer, 2, " " ) )
            oFile:cClass += Lower( hb_TokenGet( cTrimBuffer, 1, " " ) ) + " " //StrTran( cUpperBuffer, "CLASS ", "class ") 
            oFile:cClass += Upper( hb_TokenGet( cTrimBuffer, 2, " " ) ) + hb_eol()
            oFile:cClass += "{" + hb_eol() + "};" + hb_eol() 

            oFile:lIniClass := .f.
            oFile:lClass    := .t.
            oFile:lEndClass := .f.
            oFile:cRetVal := oFile:cClass + hb_eol()

         EndIf

         If oFile:lEndClass
            oFile:cRetVal += oFile:cMethod
            oFile:lIniClass := .f.
            oFile:lClass    := .f.
            oFile:lEndClass := .f.
         EndIf



         /* Acciones relacionadas con symbolo de tipo METODO */
         If oFile:lIniMethod .and. oFile:cSymbol == __METH
            
            oFile:cMethodName := hb_TokenGet( cTrimBuffer, 2, " " ) 
            oFile:cMethodName := hb_TokenGet( oFile:cMethodName, 1, "(" ) + "() " + hb_eol()
            
            if ( "NEW()" $ Upper( oFile:cMethodName ) ) .and. Empty( oFile:cDoxy )
               oFile:cMethod += "  /"+"*"+"* \brief Metodo Constructor. "+ENDCOMMENT+ hb_eol()
            else
               oFile:cMethod += hb_eol() + hb_eol() + oFile:cDoxy 
               oFile:cDoxy := ""
            endif

            if Empty(oFile:cMethod) ; oFile:cMethod := hb_eol() ; endif

            oFile:cMethod += " /** " + hb_eol() 
            oFile:cMethod += Build_Params( cBuffer, .t., oFile )
            oFile:cMethod += "  * \fn " + Lower( oFile:cClassName ) + "|" + oFile:cMethodName
            oFile:cMethod += "  * \memberof " + oFile:cClassName + hb_eol()
            oFile:cMethod += "  * " + hb_eol() + "  "+ENDCOMMENT+" " + hb_eol()

         EndIf


         /* Comentarios compatibles con Doxygen */
         If oFile:lReturn
            If !oFile:lIniComment .and. oFile:lIniDoxy
                  oFile:cPreFunc += Doxy_Convert( oFile, cBuffer ) //+ hb_eol()
            EndIf
            If !(oFile:lIniComment .or. oFile:lIniDoxy)
               oFile:cFunc += "  * " + Doxy_Convert( oFile, cBuffer ) //+ hb_eol()
            EndIf
         EndIf

         If  oFile:lIniDoxy .and. !oFile:lIniComment .and. ;
            !oFile:lReturn .and. !oFile:lIniMethod .and. oFile:lEndFile
            oFile:cRetVal += Doxy_Convert( oFile, cBuffer ) //+ hb_eol()
         EndIf

         If oFile:lIniDoxy .and. !oFile:lIniComment .and. oFile:lEndFile
            oFile:cDoxy += Doxy_Convert( oFile, cBuffer )
         EndIf

         If oFile:lIniFile .and. oFile:lEndDoxy .and. oFile:lIncSrc
            oFile:cIniFile += hb_eol()
            oFile:cIniFile += " \date 2004 - "+AllTrim(Str(Year(Date())))+" <br>"+hb_eol()
            oFile:cIniFile += " \copyright <b>(c) LGPL License. </b><br>"+hb_eol()
            oFile:cIniFile += Doxy_Convert( oFile, " \tgtk_src ", .t. )
            oFile:cIniFile += " *"+"/"+hb_eol()
         EndIf

      Else
         /* De acuerdo a las variables debe incorporar o no... */

         if oFile:lFunction .and. oFile:lIniDoxy .and. oFile:lReturn//.and. !empty(oFile:cPreFunc)
            oFile:cPreFunc += Doxy_Convert( oFile, cBuffer )
         endif

         if Empty( cTrimBuffer )
            LOOP
         endif

         If oFile:lIniDoxy .and. !oFile:lIniComment
            oFile:cDoxy += Doxy_Convert( oFile, cBuffer )
         EndIf
        
         if oFile:lFunction .and. ;
            !( oFile:lIniComment .or. oFile:lIniDoxy )
            oFile:cFunc += "  * " + cBuffer + hb_eol()
         endif 

      EndIf

      /* headers */
      if ( Left(cTrimBuffer,1) = "#" ) ; oFile:cRetVal += cBuffer + hb_eol() ; endif )

      /* se arma el texto que contiene informacion del archivo */
      If !oFile:lEndFile .and. oFile:lIniDoxy .and. !oFile:lIniComment ;
         .and. Empty( oFile:cFunc ) .and. Empty( oFile:cClass ) 

         oFile:lIniFile := .t.
         oFile:cIniFile += Doxy_Convert( oFile, cBuffer, .t. )
         if oFile:lEndDoxy
            //oFile:cRetVal += oFile:cIniFile
            //oFile:cIniFile := ""
            oFile:lEndFile := .t.
         endif
      endif

      /* Inicializamos valores de bloques si inician y finalizan */
      if oFile:lIniComment .and. oFile:lEndComment
         oFile:lIniComment := .f.
         oFile:lEndComment := .f.
      endif

      if oFile:lIniDoxy .and. oFile:lEndDoxy
         oFile:lIniDoxy := .f.
         oFile:lEndDoxy := .f.
      endif



   EndDo

   if !hb_DirExists( oFile:cDoxyDir ) ; hb_DirCreate( oFile:cDoxyDir ) ; endif

   hb_MemoWrit( oFile:cDoxyDir+"/"+cfile, oFile:cIniFile + ;
                              oFile:cIniCode + ;
                              oFile:cRetVal )

   FClose( aHandle[ 1 ] )

   /* Enviamos archivos de JavaScript a la carpeta correspondiente */
   if !hb_DirExists( "./html" )                ; hb_DirCreate( "./html" )                ; endif
   if !hb_DirExists( "./html/syntax" )         ; hb_DirCreate( "./html/syntax" )         ; endif
   if !hb_DirExists( "./html/syntax/styles" )  ; hb_DirCreate( "./html/syntax/styles" )  ; endif
   if !hb_DirExists( "./html/syntax/scripts" ) ; hb_DirCreate( "./html/syntax/scripts" ) ; endif
   
   CopyDir( "syntaxhighlighter/scripts", "./html/syntax/scripts" )
   CopyDir( "syntaxhighlighter/styles", "./html/syntax/styles" )

return .t.


/** \brief Copia el contenido de la carpeta <i>cSource</i> a <i>cDest</i>.
  * Almacena el numero de archivos copiados en la variable <i>nCopied</i>
  * \todo 
  * - Crear la funcionalidad de crear los directorios que no existan.
  * \hb_example
  * \code
  *  CopyDir("/t-gtk/include", "./include", @nFiles)
  *  ? nFiles, "Archivos Copiados."
  * \endcode
  */
FUNCTION CopyDir( cSource, cDest, nCopied)
  
  Local cFile, I, cDir, nFiles, aFiles

  Default nCopied to 0
//  Default cSource to "C:\SISTEMAS\*"
//  Default cDest to "D"

  if ( Right( cSource, 1 ) != hb_ps() ) ; cSource += hb_ps() ; endif
  if ( Right( cDest, 1 ) != hb_ps() ) ; cDest += hb_ps() ; endif

  aFiles := DirectoryRecurse(cSource)

  nFiles := Len( aFiles )

  For i := 1 to nFiles
     cFile := aFiles[i,1]
     cDir := cDest + Subs( FilePath(cFile), 2, Len(cFile) )
     makedir( cDir )
     If IsDirectory( cFile )
        MakeDir(StrTran(cFile,cSource, cDest))
     else
        __CopyFile( cFile, StrTran(cFile,cSource, cDest) )
     endif
  Next I
  nCopied := I
return nil


/** \brief Retorna la ruta del archivo <i>cFile</i> */
FUNCTION FilePath( cFile )
   LOCAL nPos, cFilePath
   If (nPos := RAT(hb_ps(), cFile)) != 0
     cFilePath := SUBSTR( cFile, 1, nPos )
   Else
     cFilePath := ""
   EndIf
RETURN cFilePath 


/** \brief Realiza la lectura de la siguiente linea del archivo en proceso.  */
STATIC FUNCTION FReadLn( aHandle, cBuffer, oFile,nMaxLine )
   STATIC s_aEOL := { Chr( 13 ) + Chr( 10 ), Chr( 10 ), Chr( 13 ) }
   LOCAL cLine, nSavePos, nEol, nNumRead, nLenEol, idx
   LOCAL cBufferNext := ""
   LOCAL cBufferClean:= ""
   LOCAL cTrimBuffer

   hb_default( @nMaxLine, 256 )

   cBuffer := ""

   nSavePos := FSeek( aHandle[ 1 ], 0, FS_RELATIVE )
   cLine := Space( nMaxLine )
   nNumRead := FRead( aHandle[ 1 ], @cLine, hb_BLen( cLine ) )
   cLine := hb_BLeft( cLine, nNumRead )

   nEol := 0
   FOR idx := 1 To Len( s_aEOL )
      IF ( nEol := At( s_aEOL[ idx ], cLine ) ) > 0
         nLenEol := hb_BLen( s_aEOL[ idx ] ) - 1
         Exit
      ENDIF
   NEXT

   IF nEol == 0
      cBuffer := cLine
   ELSE
      cBuffer := Left( cLine, nEol - 1 )
      FSeek( aHandle[ 1 ], nSavePos + hb_BLen( cBuffer ) + 1 + nLenEol, FS_SET )
   ENDIF

   aHandle[ 2 ]++

   cBufferClean := AllTrim( Del_Comment( cBuffer ) )
   if Right( cBufferClean, 1 ) = ";"
      FReadLn( @aHandle, @cBufferNext )
      cBuffer := AllTrim( Left( cBufferClean, Len( cBufferClean ) - 1 ) )
      cBuffer += AllTrim( cBufferNext )
   endif

/*
   cTrimBuffer := AllTrim( cBuffer )
   If hb_TokenGet( Upper( cTrimBuffer ), 1, " " ) = "STATIC" 
      cBuffer := Right( cTrimBuffer, Len( cTrimBuffer ) - 7 )
   EndIf
*/
   if nNumRead !=0 .and. !hb_IsNil(oFile) ; oFile:nLines++ ; endif

   RETURN nNumRead != 0




/*
 *
 *    FUNCIONES DE ANALISIS DE CADENAS
 *
 *
 */

STATIC FUNCTION GET_SYMBOL(cBuffer, oFile )

  LOCAL nPos
  LOCAL cSymbol
  LOCAL cToken

  cBuffer := ReplRight( cBuffer , " " , hb_eol() )
  cToken  := hb_TokenGet( cBuffer, 1, " " )

  If cToken = "STATIC"
     cToken  := hb_TokenGet( cBuffer, 2, " " )
  EndIf

  If Left(cToken,2)=="//" ; return .f. ; EndIf 

  If hb_ISNIL(oFile) ; Return NIL ; EndIf

   //nPos := hb_AScan( aSymbols, {| cSymbol | qout("compare ",cSymbol,"with",cToken),(cSymbol == cToken )  } ) 
   nPos := hb_AScan( aSymbols, {| cSymbol | (cSymbol == cToken )  } ) 
   If nPos = 0
      Return .F.
   EndIf
   cSymbol := aSymbols[nPos]
   oFile:cSymbol := cSymbol
   //oFile:cRetVal := ""

   If Len(cBuffer) >= Len( cSymbol ) .AND. ( cSymbol == cToken )
//? "Encontrado Simbolo "+cSymbol+" en: "+cBuffer+hb_eol()
      Do Case
      Case cSymbol = __METH
         oFile:lIniMethod := .t.
         Return .t.

      Case cSymbol = __CLAS  
         oFile:lIniClass := .t.
         Return .t.

      Case cSymbol = __ENDC 
         oFile:lEndClass := .t.
         Return .t.
         

      Case cSymbol = __FUNC .or. cSymbol = __PROC //.and. oFile:lIniFunc 
         if oFile:lIniFunc ; oFile:lEndFunc := .t. ; endif
         oFile:lIniFunc := .t.
         oFile:lReturn  := .f.


      Case cSymbol = __RETU
         if !( oFile:lIniComment .or. oFile:lIniDoxy )
            oFile:lReturn := .t.
         endif

      Case ( cSymbol $ __IDOX ) .and.  ;
           ( ( __IDOX $ cBuffer ) .and. ( __EDOX $ cBuffer ) )
         oFile:lIniDoxy := .t.
         oFile:lEndDoxy := .t.
         return .t.

      Case cSymbol = __IDOX //.and. !oFile:lIniComment
         oFile:lIniDoxy := .t.
         if oFile:lEndComment
            oFile:lIniComment := .f.
            oFile:lEndComment := .f.
            oFile:lComment    := .f.
            return .t.
         endif
         if oFile:lEndDoxy
            oFile:lEndDoxy := .f.
            return .t.
         endif

      Case cSymbol = __EDOX //.and. oFile:lIniDoxy
         if oFile:lIniDoxy 
            if oFile:lEndComment
               oFile:lIniComment := .f.
               oFile:lComment    := .f.
               oFile:lEndComment := .f.
            endif
            oFile:lEndDoxy := .t. 
            return .t.
         endif
         if oFile:lIniComment
            oFile:lIniCommet  := .f.
            oFile:lComment    := .f.
            oFile:lIgnore     := .f.
            oFile:lEndComment := .t.
         endif
         return .t.

      Case cSymbol = __COMM
         If ( Left( cBuffer,3 ) != __IDOX ) // Diferente a comentario tipo doxygen
            oFile:lIniComment := .t. 
            oFile:lComment    := .t.
            oFile:lIgnore     := .t.
         EndIf
         If ( __EDOX $ cBuffer ) .and. oFile:lIniComment // Si finaliza el comentario... ignoramos.
            oFile:lIniComment := .f.
            oFile:lComment    := .f.
            oFile:lIgnore     := .f.
            oFile:lEndComment := .f.
            Return .f.
         EndIf

         If ( __EDOX $ cBuffer ) .and. oFile:lIniDoxy // Si finaliza el comentario... ignoramos.
            oFile:lEndDoxy    := .t.
            Return .f.
         EndIf

      EndCase
      Return .T.
   EndIf

RETURN .F.



STATIC FUNCTION BUILD_PARAMS( cBuff, lDoxy, oFile )
   Local aTokens
   Local cToken
   Local cLocalBuff:=""
   Local aParam
   Local nPos:=0
   Local lInitial := .f.
   Local lIgnore := .f.

   Default lDoxy To .t.

   aTokens := {} //   aTokens := hb_ATokens( cBuff, " " )
   FOR EACH cToken IN cBuff

       Do Case
       Case cToken="(" .and. !lInitial //nPos > 0 
          lInitial   := .t.

       Case cToken=")" .and. lIgnore
          cLocalBuff += cToken
          lIgnore := !lIgnore

       Case cToken=")" .and. lInitial
          AAdd( aTokens, cLocalBuff )
          lIgnore:=.f.
          exit

       Case cToken=","
          AAdd( aTokens, cLocalBuff )
          cLocalBuff := ""

       Case cToken="(" .and. lInitial  //debe ignorar hasta el cierre del parentesis.
          cLocalBuff += cToken
          lIgnore:=.t.

       Case cToken=" "

       OtherWise
          If lInitial .and. !lIgnore 
             if Len(cLocalBuff)!=1 ; cToken := Lower(cToken) ; endif
             cLocalBuff += cToken 
          endif
          
       EndCase    
       //? cToken, " - ", cToken:__EnumIndex()
       //? aTokens[ cToken:__EnumIndex() ]," --> ", cToken:__EnumIndex()
   NEXT 
   //AEval( aTokens, {|a| qout(" - ",a) } ) //hb_NumToken

   If lDoxy
      cLocalBuff := ""
      FOR EACH aParam IN aTokens
         cLocalBuff += "  * @param " + aParam + hb_eol()
      NEXT
      Return cLocalBuff
   EndIf

RETURN aTokens




STATIC FUNCTION DEL_COMMENT( cBuff )

   Local cPreComment
   Local cTrimBuffer := AllTrim( cBuff )

   If ("//" $ cBuff)
      cPreComment := hb_TokenGet(cBuff, 1, "//" )      
      Return ALLTRIM( cPreComment ) //hb_TokenGet(cBuff, 1, "//" )+hb_eol()

   EndIf

   If ( Left( cBuff,4 ) == "/** " )
      return cBuff
   EndIf 

   If ("/*" $ cBuff)
      cPreComment := hb_TokenGet(cBuff, 1, "/*" )      
    
      If Left( cPreComment, 1 )!="*" 
         Return ALLTRIM( cPreComment ) 
      EndIf

   EndIf

   If ("* " $ Left(AllTrim(cBuff), 2 ) )
      cPreComment := hb_TokenGet(cBuff, 1, "*" )      
      Return ALLTRIM( cPreComment ) //hb_TokenGet(cBuff, 1, "//" )+hb_eol()
   EndIf

RETURN cBuff


/** \brief Realiza conversion de valores simples desde prg original   */
STATIC FUNCTION DOXY_CONVERT( oFile, cBuffer, lForce )
   Local cTrimBuffer 
   Local cResult := ""

   default lForce TO .f.

   if ( oFile:lIniDoxy .or. lForce )

      cTrimBuffer := AllTrim( Lower( cBuffer ) )

      if ( "\file_tgtk" $ cBuffer ) //.and. oFile:lIniFile
         if ( "/** " $ cTrimBuffer ) ; cResult := "/"+"** " + hb_eol() ; endif
         cResult += "\file "+StrTran(oFile:cFile, "/", "" ) + hb_eol()
//msg_info(cResult)
         oFile:lIncSrc := .t.
         return cResult
      endif

      if ( "\tgtk_"+"src" $ cBuffer )
//         if ( "/** " $ cTrimBuffer ) ; cResult := "/"+"** " + hb_eol() ; endif
//         cResult += "\file "+StrTran(oFile:cFile, "/", "" ) + hb_eol()
         cResult += "  \html"+"only " + hb_eol()
         cResult += "   </dl>"+hb_eol()
         cResult += "<dl class='source'><dt><b>Código Fuente:</b></dt> " 
         cResult += "   <dd><a name='_htmlsrc' href='" + ;
                        Path_To_Html( oFile, oFile:cReposPath + oFile:cFile ) + "' " + ;
                        "target='_blank' style='font-size:8pt;'>"+oFile:cFile+"</a><br><dl></dl>" + hb_eol()
         cResult += "  \endhtml"+"only " + hb_eol()
//msg_info( cResult, oFile:cFile )
         oFile:lIncSrc := .f.
         return cResult
      endif

      if ( "\"+"code_hb" $ cTrimBuffer )
         cResult += " \html"+"only "+hb_eol()
         if !oFile:lIniCode
            oFile:cIniCode := "/"+"** "+hb_eol()
            oFile:cIniCode += " \html"+"only "+hb_eol()

            oFile:cIniCode += " <script type='text/javascript' src='"+oFile:cHLPath
            oFile:cIniCode +="scripts/shCore.js'></script>" + hb_eol()
            oFile:cIniCode += " <script type='text/javascript' src='"+oFile:cHLPath
            oFile:cIniCode +="scripts/shBrushHarbour.js'></script>" + hb_eol()
            oFile:cIniCode += " <link type='text/css' rel='stylesheet' href='"
            oFile:cIniCode += oFile:cHLPath + "styles/"
            oFile:cIniCode += oFile:cStyleSheet+ "'/> " + hb_eol()
            oFile:cIniCode += " <script type='text/javascript'>"
            oFile:cIniCode +=   "SyntaxHighlighter.defaults['first-line'] = 1;" + hb_eol()
            oFile:cIniCode +=   "SyntaxHighlighter.defaults['tab-size']   = 4;" + hb_eol()
            oFile:cIniCode +=   "SyntaxHighlighter.defaults['collapse']  = true;" + hb_eol()
            oFile:cIniCode +=   "SyntaxHighlighter.defaults['ruler']  = true;" + hb_eol()
            oFile:cIniCode +=   "SyntaxHighlighter.all();" + hb_eol()
            oFile:cIniCode += " </script>" + hb_eol()
/*
         oFile:cIniCode += " <link rel='stylesheet' title='Default' href='"
         oFile:cIniCode += oFile:cHLPath + "styles/"
         oFile:cIniCode += oFile:cStyleSheet+ "'> " + hb_eol()
         oFile:cIniCode += "<script src='"
         oFile:cIniCode += oFile:cHLPath + "highlight.pack.js'></script>" + hb_eol()
         oFile:cIniCode += "<script> " + hb_eol()
         oFile:cIniCode += "  hljs.tabReplace = '    ';" + hb_eol()
         oFile:cIniCode += "  hljs.initHighlightingOnLoad(); " + hb_eol()
         oFile:cIniCode += "</script> " + hb_eol()
*/
            oFile:cIniCode += " \endhtml"+"only "+hb_eol()
            oFile:cIniCode += " *"+"/ "+hb_eol()
            oFile:lIniCode := .t.
         endif
//         cResult += "<style>" + hb_eol()
//         cResult += " <script type='text/javascript' title='Fichero Fuente'" + hb_eol()
//         cResult += ".class_code {border: 1px solid #000;} " + hb_eol()
//         cResult += ".syntaxhighlighter .line.alt2 {background-color: rgb(245,245,245);} </style> " + hb_eol()
//         cResult += '<pre class="brush: hb; title="Fichero Fuente" class-name: '+"'class_code'"+'">' + hb_eol() //"class='javascript'> " + hb_eol()
         cResult += "<pre class='brush: hb' title='Ver Fuente'>" + hb_eol() //"class='javascript'> " + hb_eol()
         return cResult
      endif

      if ( "\"+"endcode_hb" $ cTrimBuffer )
         cResult += "</pre>" + hb_eol()
         cResult += " \end"+"htmlonly" + hb_eol()
         return cResult
      endif

      if ( "\"+"hb_example" $ cTrimBuffer )
         cResult += "<dl><b>Ejemplo:</b>" + hb_eol()
         return cResult
      endif

      if ( "\"+"author" $ cTrimBuffer )
         cResult += StrTran( cBuffer, "<", "<em!!<" ) 
         cResult := StrTran( cResult, ">", "></em>" ) 
         cResult := StrTran( cResult, "!!", ">" ) 
         cResult += hb_eol()
         return cResult
      endif

   endif

   cResult += cBuffer + hb_eol()
   
RETURN cResult


/** \brief Traduce la ruta indicada en el archivo fuente para ser localizada en el repositorio web. */
STATIC FUNCTION PATH_TO_HTML( oFile, cPath )
   LOCAL cResult
   Local cFilePath := ""

? cPath
   cFilePath := "&path=%2Ftrunk%2F"+StrTran( cPath, "/", "%2F" )
   if !( ( ".prg" $ cPath ) .or. ( ".ch" $ cPath ) )
      cFilePath += AllTrim( Lower( oFile:cFile ) )
   endif
   cResult := oFile:cWWW+"/filedetails.php?repname="+oFile:cReposName
   cResult += cFilePath
RETURN cResult



//eof

